﻿using System.Linq;
using Best.SmartCms.Dto.Common;
using Best.SmartCms.Dto.Enums;
using Best.SmartCms.Dto.Response;
using Best.SmartCms.Service.BizException;
using Best.SmartCms.Service.Common;
using Best.SmartCms.Service.Security;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.AspNetCore.Mvc.Filters;

namespace Best.SmartCms.API.WebAPIExtensions
{
    /// <summary>
    /// 
    /// </summary>
    public class TokenAuthorizeAttribute : TypeFilterAttribute
    {
        /// <summary>
        /// 
        /// </summary>
        public TokenAuthorizeAttribute() : base(typeof(TokenAuthorizationFilter))
        {
            Arguments = new object[] { };
        }
    }

    /// <summary>
    /// Token 验证
    /// </summary>
    public class TokenAuthorizationFilter : IAuthorizationFilter
    {
        private readonly WorkContext _workContext;
        private readonly LoginTokenService _loginTokenService;
        private readonly UserService _userService;
        /// <summary>
        /// 
        /// </summary>
        /// <param name="workContext"></param>
        /// <param name="loginTokenService"></param>
        /// <param name="userService"></param>
        public TokenAuthorizationFilter(WorkContext workContext, LoginTokenService loginTokenService, UserService userService)
        {
            _workContext = workContext;
            _loginTokenService = loginTokenService;
            _userService = userService;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="context"></param>
        public void OnAuthorization(AuthorizationFilterContext context)
        {
            try
            {
                if (!Validate(context))
                {
                    context.Result = new UnauthorizedResult();
                }
            }
            catch (ForceLogoutException e)
            {
                context.Result = new JsonResult(new ApiResponse()
                {
                    Code = e.ExceptionCode,
                    Message = e.Message,
                    Success = false
                });
            }
            catch (BizExceptionBase)
            {
                context.Result = new UnauthorizedResult();
            }
        }

        private bool Validate(AuthorizationFilterContext context)
        {
            // 如果采用3.1 Endpoint方式采用如下过滤AllowAnonymous.
            var endpoint = context.HttpContext.GetEndpoint();
            if (endpoint?.Metadata?.GetMetadata<IAllowAnonymous>() != null)
            {
                return true;
            }

            // 如果采用 2.2 Startup  app.UseMvc(); 方式，则用如下过滤AllowAnonymous
            //if (context.Filters.Any(f => f is AllowAnonymousFilter))
            //{
            //    return true;
            //}

            if (context.Filters.Any(f => f is SignatureAttribute))
            {
                //外部系统Token认证
                return true;
            }

            #region 系统正常授权认证

            var uid = context.HttpContext.User.FindFirst(Claims.Uid);
            if (uid == null)
            {
                return false;
            }

            var userId = uid.Value;
            var token = context.HttpContext.User.FindFirst(Claims.Token);
            if (token == null)
            {
                return false;
            }


            var phone = context.HttpContext.User.FindFirst(Claims.Phone);
            if (string.IsNullOrEmpty(phone?.Value))
            {
                return false;
            }

            if (!_loginTokenService.VerifyToken(phone.Value, token.Value))
            {
                return false;
            }

            var source = context.HttpContext.User.FindFirst(Claims.Source);
            var user = _userService.FindById(long.Parse(userId));
            if (user == null)
            {
                return false;
            }

            if (!user.Enabled)
            {
                return false;
            }

            _workContext.CurrentUser = user;
            _workContext.Source = (RequestSourceEnum) int.Parse(source.Value);
            return true;

            #endregion

        }

        
    }
}
